﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using static System.Math;

namespace WindLoad
{
    public static class ArrayHelper
    {
        public static double Interpolate(this IList<double> xs, double index)
        {
            var endIndex = xs.Count - 1;
            Debug.Assert(0 <= index && index <= endIndex);
            var i = (int) Floor(index);
            return i < endIndex ? Interpolate(xs[i], xs[i + 1], index - i) : xs[endIndex];
        }

        public static double Interpolate(this double[,] data, double rowIndex, double colIndex)
        {
            var rowUpperBound = data.GetLength(0) - 1;
            var colUpperBound = data.GetLength(1) - 1;
            Debug.Assert(data.GetLength(0) >= 2 && data.GetLength(1) >= 2 &&
                         0 <= rowIndex && rowIndex <= rowUpperBound &&
                         0 <= colIndex && colIndex <= colUpperBound);
            var row = (int) Floor(rowIndex);
            var col = (int) Floor(colIndex);
            if (row >= rowUpperBound)
                row--;
            if (col >= colUpperBound)
                col--;

            var x1 = Interpolate(data[row, col], data[row + 1, col], rowIndex - row);
            var x2 = Interpolate(data[row, col + 1], data[row + 1, col + 1], rowIndex - row);
            return Interpolate(x1, x2, colIndex - col);
        }

        public static double Interpolate(double x1, double x2, double ratio)
            => x1 + (x2 - x1) * ratio;

        public static double GetIndex(this IList<double> xs, double x)
        {
            if (x <= xs[0])
                return 0;

            if (x >= xs[xs.Count - 1])
                return xs.Count - 1;

            var index = 0D;
            for (var i = 0; i < xs.Count; i++)
            {
                var x1 = xs[i];
                var x2 = xs[i + 1];
                Debug.Assert(x1 < x2);
                if (x1 <= x && x < x2)
                {
                    index = i + (x - x1) / (x2 - x1);
                    break;
                }
            }

            return index;
        }

        public static double[] GetRow(this double[,] array, int row)
        {
            var cols = array.GetUpperBound(1) + 1;
            var result = new double[cols];
            const int size = sizeof(double);
            Buffer.BlockCopy(array, row * cols * size, result, 0, cols * size);
            return result;
        }
    }
}